// Effective C++ 条款24：若所有参数皆需类型转换，请为此采用non-member函数

// 核心原则
// 当你需要为某个函数的所有参数（包括this指针所指向的那个隐含参数）进行类型转换时，那么这个函数必须是非成员函数。

// 问题背景
// 在C++中，隐式类型转换不适用于this指针（即对象本身）。这导致了一个常见的问题：当你希望支持混合类型运算时，成员函数会导致不对称的行为。

// 详细解释与示例
// 假设我们有一个表示有理数的类：
class Rational
{
public:
    Rational(int numerator = 0, int denominator = 1);

    // 成员函数实现的乘法
    Rational operator*(const Rational &rhs) const;

private:
    int numerator;
    int denominator;
};
// 使用这个类：
Rational oneHalf(1, 2);
Rational result;

// 这些调用都能工作
result = oneHalf * oneHalf; // oneHalf.operator*(oneHalf)
result = oneHalf * 2;       // oneHalf.operator*(Rational(2))

// 但这个调用无法工作！
result = 2 * oneHalf; // 2.operator*(oneHalf)? - 不存在这样的函数!
// 最后一行代码无法编译，因为2是一个int，它没有operator*成员函数。
// 编译器也不会尝试将2转换为Rational对象然后调用其成员函数，因为隐式类型转换不适用于this指针。

// 解决方案
// 将运算符重载实现为非成员函数：
class Rational
{
public:
    Rational(int numerator = 0, int denominator = 1);

    // 不再有成员operator*

    // 但我们需要访问器函数
    int numerator() const;
    int denominator() const;

private:
    int num;
    int den;
};

// 非成员函数实现
const Rational operator*(const Rational &lhs, const Rational &rhs)
{
    return Rational(lhs.numerator() * rhs.numerator(),
                    lhs.denominator() * rhs.denominator());
}

// 现在，这些调用都能正常工作：
Rational oneHalf(1, 2);
Rational result;

result = oneHalf * oneHalf; // operator*(oneHalf, oneHalf)
result = oneHalf * 2;       // operator*(oneHalf, Rational(2))
result = 2 * oneHalf;       // operator*(Rational(2), oneHalf) - 现在可以工作了!

// 为什么这样有效
// 当编译器看到2 * oneHalf时，它会：
// 1.查找是否有全局函数operator*(int, Rational)
// 2.如果没有，查找是否有可以通过隐式转换调用的函数
// 3.发现operator*(Rational, Rational)，并尝试将2转换为Rational
// 4.调用operator*(Rational(2), oneHalf)

// 何时应用这个条款
// 这个条款主要适用于：

// 1.重载运算符（如+, -, *, /, ==等）
// 2.需要支持与内置类型或其他用户定义类型的混合运算的函数
// 3.任何你希望第一个参数能够进行隐式类型转换的函数

// 总结
// 1.当函数需要对所有参数（包括调用对象自身）进行类型转换时，应该将其实现为非成员函数
// 2.这主要适用于运算符重载和需要支持混合类型运算的情况
// 3.这个条款是C++特有的，因为它源于C++的隐式类型转换规则
// 4.这是条款23的一个特殊但重要的应用场景
// 5.这个条款展示了C++语言细节如何影响设计决策，理解它有助于创建更直观、更易用的类接口。